home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 406_01 / atoc / preproc.c < prev    next >
Text File  |  1993-11-09  |  6KB  |  205 lines

  1. /*=========================================================================
  2.  
  3.     ATOC proprocessor module
  4.  
  5. =========================================================================*/
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include "atoc.h"
  10.  
  11.  
  12. #define STACKSIZE        32
  13. #define INCLUDE_ENVNAME        "INCLUDE"
  14.  
  15.  
  16. /*-------------------------------------------------------------------------
  17. local global variables
  18. -------------------------------------------------------------------------*/
  19. PRIVATE int ecstack[ STACKSIZE ];    /* stack for endifcount nesting */
  20. PRIVATE int csi = 0;            /* current stack index */
  21.  
  22.  
  23. /*-------------------------------------------------------------------------
  24. preprocessor( fo, s ) alters new ANSI preprocessor statements into those
  25. commonly supported by older compilers. Also notes a few things we don't
  26. handle yet.
  27. -------------------------------------------------------------------------*/
  28. preprocessor( fo, s )
  29. FILE *fo;
  30. char *s;
  31. {
  32.     char *p1, *p2, *p3, *strstr();
  33.  
  34.     /* find first non-white char */
  35.     for ( p1 = s; *p1 && isspace( *p1 ); ++p1 )
  36.         ;
  37.  
  38.     if ( *p1 == '#' )
  39.     {
  40.         /* remove leading white space */
  41.         /* and any white space between # and command */
  42.         for ( ++p1; *p1 && isspace( *p1 ); ++p1 )
  43.             ;
  44.         s[ 0 ] = '#';
  45.         if ( p1 > &s[ 1 ] )
  46.             strcpy( &s[ 1 ], p1 );
  47.  
  48.         /* check for #if, handle nesting of endifcount */
  49.         if ( ( p1 = strstr( s, "#if" ) ) != NULL )
  50.         {
  51.             if ( csi < STACKSIZE )
  52.             {
  53.                 ecstack[ csi++ ] = endifcount;
  54.                 endifcount = 0;
  55.             }
  56.             else
  57.             {
  58.                 error( "#if stack overflow" );
  59.                 return;
  60.             }
  61.         }
  62.  
  63.         /* check for #elif, convert to #else #if and add extra #endif */
  64.         if ( ( p1 = strstr( s, "#elif" ) ) != NULL )
  65.         {
  66.             fprintf( fo, "#else\n" );
  67.             strcpy( p1 + 1, p1 + 3 );
  68.             ++endifcount;
  69.         }
  70.  
  71.         /* check for "#if defined" or "#if ! defined" */
  72.         if ( ( p1 = strstr( s, "#if" ) ) != NULL )
  73.         {
  74.             p2 = strstr( p1, "!" );
  75.             if ( ( p3 = strstr( p1, "defined" ) ) != NULL )
  76.             {
  77.                 strcpy( p1, p3 + 7 );
  78.                 if ( p2 && p2 > p1 && p2 < p3 )
  79.                     strins( p1, "#ifndef" );
  80.                 else strins( p1, "#ifdef" );
  81.             }
  82.         }
  83.  
  84.         /* output any accumulated #endifs */
  85.         if ( ( p1 = strstr( s, "#endif" ) ) != NULL )
  86.         {
  87.             for ( ; endifcount; --endifcount )
  88.                 fprintf( fo, "#endif\n" );
  89.             if ( csi > 0 )
  90.             {
  91.                 endifcount = ecstack[ --csi ];
  92.             }
  93.             else
  94.             {
  95.                 error( "Too many #endifs" );
  96.                 return;
  97.             }
  98.         }
  99.  
  100.         /* handle include files if option selected */
  101.         if ( ( p1 = strstr( s, "#include" ) ) != NULL )
  102.         {
  103.             if ( includeflag )
  104.                 include( fo, s );
  105.             /* else just output the include line */
  106.         }
  107.  
  108.         /* check for new # and ## operators that we don't convert */
  109.         if ( ( p1 = strstr( s, "#define" ) ) != NULL )
  110.         {
  111.             if ( strstr( p1 + 7, "##" ) != NULL )
  112.                 warning( "'##' Token paste operator not converted" );
  113.             else if ( strstr( p1 + 7, "#" ) != NULL )
  114.                 warning( "'#' String literal operator not converted" );
  115.         }
  116.     }
  117. }
  118. /*-------------------------------------------------------------------------
  119. endif_stack_empty() checks to see if the stack is empty, which it should
  120. be at the time we call.
  121. -------------------------------------------------------------------------*/
  122. int endif_stack_empty()
  123. {
  124.     if ( csi == 0 )
  125.         return( TRUE );
  126.     else return( FALSE );
  127. }
  128. /*-------------------------------------------------------------------------
  129. include( fo, s ) handles an include file line. This is only done if the
  130. -i option was specified on the command line. -il causes us to only handle
  131. local includes (those delimited with " ").
  132. -------------------------------------------------------------------------*/
  133. PRIVATE include( fo, s )
  134. FILE *fo;
  135. char *s;
  136. {
  137.     FILE *fi;
  138.     char basename[ 80 ], fullname[ 80 ], old_filename[ 80 ];
  139.     char *cp, dc, *path, *getenv(), *strchr();
  140.     int old_linenumber;
  141.  
  142.     /* find include filename and delimiter type */
  143.     if ( ( cp = strchr( s, '\"' ) ) == NULL )
  144.         cp = strchr( s, '<' );
  145.     if ( cp != NULL )
  146.     {
  147.         dc = *cp++;
  148.         /* if local includes only and this is a <>, forget it... */
  149.         if ( localonlyflag && dc == '<' )
  150.             return;
  151.     }
  152.     else
  153.     {
  154.         error( "Can't find include filename delimiter" );
  155.         return;
  156.     }
  157.  
  158.     /* copy include filename to basename, delete trailing end of line */
  159.     strcpy( basename, cp );
  160.     if ( dc == '<' )
  161.         dc = '>';
  162.     if ( ( cp = strchr( basename, dc ) ) != NULL )
  163.         *cp = '\0';
  164.     else
  165.     {
  166.         error( "No trailing delimiter on include filename" );
  167.         return;
  168.     }
  169.  
  170.     /* open include file, either locally... */
  171.     if ( dc == '\"' )
  172.         fi = fopen( basename, "r" );
  173.     else fi = NULL;
  174.     /* or on the INCLUDE path */
  175.     if ( fi == NULL )
  176.         if ( path = getenv( INCLUDE_ENVNAME ) )
  177.             for ( cp = path; path; path = cp )
  178.             {
  179.                 if ( ( cp = strchr( cp, ';' ) ) != NULL )
  180.                     *cp++ = '\0';
  181.                 strcpy( fullname, path );
  182.                 strcat( fullname, "\\" );
  183.                 strcat( fullname, basename );
  184.                 if ( ( fi = fopen( fullname, "r" ) ) != NULL )
  185.                     break;
  186.             }
  187.  
  188.     /* set up global variables and recursively call atoc() for include file */
  189.     if ( fi != NULL )
  190.     {
  191.         strcpy( old_filename, filename );
  192.         strcpy( filename, basename );
  193.         old_linenumber = linenumber;
  194.         linenumber = 1;
  195.         fprintf( fo, "/* %s */\n", s );
  196.         atoc( fi, fo );
  197.         fclose( fi );
  198.         s[ 0 ] = '\0';
  199.         strcpy( filename, old_filename );
  200.         linenumber = old_linenumber;
  201.     }
  202.     else error( "Can't open include file" );
  203. }
  204. /*=======================================================================*/
  205.